home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gsdsc.c < prev    next >
C/C++ Source or Header  |  1994-12-29  |  8KB  |  316 lines

  1. /* Copyright (C) 1994 Aladdin Enterprises.  All rights reserved. */
  2.  
  3. /* dsc.c */
  4. /* Parse DSC comments from a PostScript file. */
  5. #include "stdpre.h"
  6. #include <stdio.h>
  7. #include <malloc.h>
  8. #include <math.h>
  9. #ifndef SEEK_SET
  10. #  define SEEK_SET 0
  11. #endif
  12.  
  13. /* Define the maximum length of a line in a DSC-conforming file. */
  14. /* This is 255 characters + 2 for newline + 1 for null. */
  15. #define line_size 258
  16.  
  17. /* Test whether a line begins with %%. */
  18. #define is_dsc_comment(line) ((line)[0] == '%' && (line)[1] == '%')
  19.  
  20. /* Test whether a string begins with a given prefix. */
  21. #define has_prefix(str, pre) !strncmp(str, pre, strlen(pre))
  22. /* Faster test if prefix is a literal string. */
  23. #define has_lit_prefix(str, litpre) !strncmp(str, litpre, sizeof(litpre) - 1)
  24. /* Test whether a line is a specific DSC comment. */
  25. #define has_dsc_prefix(line, litpre)\
  26.   (is_dsc_comment(line) && has_lit_prefix(line, litpre))
  27.  
  28. /* Define a bounding box structure. */
  29. #define LLX 0
  30. #define LLY 1
  31. #define URX 2
  32. #define URY 3
  33.  
  34. /* ------ Internal routines ------ */
  35.  
  36. /* Allocate a block with malloc, exiting on failure. */
  37. private void *
  38. dsc_malloc(size_t size)
  39. {    void *blk = malloc(size);
  40.     if ( blk == 0 )
  41.       {    fprintf(stderr, "Unable to allocate object; giving up.\n");
  42.         exit(255);
  43.       }
  44.     return blk;
  45. }
  46.  
  47. /* Copy a given amount of data from one file to another (to != NULL) or */
  48. /* skip a given amount of data in a file without using fseek (to == NULL). */
  49. #define fcpy_size 5000
  50. private void
  51. fcpy(FILE *to, FILE *from, long len)
  52. {    char buf[fcpy_size];
  53.     size_t count;
  54.     for ( ; len > 0; len -= count )
  55.       {    count = (len > fcpy_size ? fcpy_size : len);
  56.         fread(buf, sizeof(char), count, from);
  57.         if ( to != NULL )
  58.           fwrite(buf, sizeof(char), count, to);
  59.       }
  60. }
  61. #undef fcpy_size
  62.  
  63. /*
  64.  * Copy (or skip) a %%BeginBinary/%%EndBinary section.
  65.  * Return the number of bytes copied or skipped.
  66.  */
  67. private long
  68. copy_binary(FILE *to, FILE *from, const char *line)
  69. {    long count;
  70.     if ( sscanf(line + 14, "%ld", &count) == 1 )
  71.       fcpy(to, from, count);
  72.     else
  73.       count = 0;
  74.     return count;
  75. }
  76.  
  77. /*
  78.  * Copy (or skip) a %%BeginData/%%EndData section.
  79.  * Return the number of bytes copied or skipped.
  80.  */
  81. private long
  82. copy_data(FILE *to, FILE *from, const char *line)
  83. {    long count, amount = 0;
  84.     char str[line_size];
  85.     str[0] = '\0';
  86.     if ( sscanf(line + 12, "%ld %*s %s", &count, str) >= 1 )
  87.       {    if ( !strcmp(str, "Lines") )
  88.           for ( ; count > 0; --count )
  89.             {    if ( !fgets(str, line_size, from) )
  90.               break;
  91.             amount += strlen(str);
  92.             if ( to != NULL )
  93.               fputs(str, to);
  94.             }
  95.         else
  96.           {    amount = count;
  97.             fcpy(to, from, count);
  98.           }
  99.       }
  100.     return amount;
  101. }
  102.  
  103. /*
  104.  * Read the next line from the input.  Skip over embedded data, and also
  105.  * skip sections (such as procsets, fonts, and included documents) that
  106.  * are not part of the main document flow.
  107.  * Return a pointer to the input line, or NULL if we reached EOF.
  108.  */
  109. private void skip_region(P4(char *, FILE *, long *, const char *));
  110. private char *
  111. next_line(char *line, FILE *in, long *pstart, long *plen)
  112. {    if ( pstart )
  113.       *pstart = ftell(in);
  114.     *plen = 0;
  115.     for ( ; ; )
  116.       {    if ( !fgets(line, line_size, in) )    /* EOF */
  117.           {    line[0] = 0;
  118.             return 0;
  119.           }
  120.         *plen += strlen(line);
  121.         if ( !has_dsc_comment(line, "Begin") )
  122.           break;
  123.         else if ( has_lit_prefix(line+7, "Binary:") )
  124.           {    *plen += copy_binary(NULL, in, line);
  125.             skip_region(line, in, plen, "EndBinary");
  126.           }
  127.         else if ( has_lit_prefix(line+7, "Data:") )
  128.           {    *plen += copy_data(NULL, in, line);
  129.             skip_region(line, in, plen, "EndData");
  130.           }
  131.         else if ( has_lit_prefix(line+7, "Feature:") )
  132.           skip_region(line, in, plen, "EndFeature");
  133.         else if ( has_lit_prefix(line+7, "File:") )
  134.           skip_region(line, in, plen, "EndFile");
  135.         else if ( has_lit_prefix(line+7, "Font:") )
  136.           skip_region(line, in, plen, "EndFont");
  137.         else if ( has_lit_prefix(line+7, "ProcSet:") )
  138.           skip_region(line, in, plen, "EndProcSet");
  139.         else if ( has_lit_prefix(line+7, "Resource:") )
  140.           skip_region(line, in, plen, "EndResource");
  141.       }
  142.     return line;
  143. }
  144. /*
  145.  * Skip a region of the PostScript file up to a given %%End comment.
  146.  */
  147. private void
  148. skip_region(char *line, FILE *in, long *plen, const char *end_comment)
  149. {    do
  150.       {    long len;
  151.         if ( next_line(line, in, NULL, &len) == NULL )
  152.           break;
  153.         *plen += len;
  154.       }
  155.     while ( !has_dsc_prefix(line, end_comment) );
  156. }
  157.  
  158. /*
  159.  * Scan a bounding box argument.  Return 1 iff we found one.
  160.  */
  161. private int
  162. scan_bbox(const char *line, int bbox[4])
  163. {    float fx0, fy0, fx1, fy1;
  164.     if ( sscanf(line, "%d %d %d %d", &bbox[LLX], &bbox[LLY],
  165.             &bbox[URX], &bbox[URY]) == 4
  166.        )
  167.       return 1;
  168.     if ( sscanf(line, "%f %f %f %f", &fx0, &fy0, &fx1, &fy1) != 4 )
  169.       return 0;
  170.     bbox[LLX] = (int)floor(fx0);
  171.     bbox[LLY] = (int)floor(fy0);
  172.     bbox[URX] = (int)ceil(fx1);
  173.     bbox[URY] = (int)ceil(fy1);
  174.     return 1;
  175. }
  176.  
  177. /*
  178.  * Scan a text argument, recognizing escapes if it is a parenthesized string.
  179.  * If the string is not parenthesized then if rest = 1, take the rest of
  180.  * the line as the argument; if rest = 0, only take up to the next whitespace.
  181.  */
  182. #define scan_text_arg(line, endp) scan_text(line, endp, 0)
  183. #define scan_line_arg(line, endp) scan_text(line, endp, 1)
  184. private const char *
  185. scan_text(const char *line, const char **endp, int rest)
  186. {    char buf[line_size];
  187.     const char *lp = line;
  188.     char *bp = buf;
  189.     char *arg;
  190.  
  191.     while ( *lp == ' ' || *lp == '\t' )
  192.       lp++;
  193.     if ( *lp == '(' )
  194.       {    int level = 1;
  195.         lp++;
  196.         for ( ; ; )
  197.           switch ( *bp++ = *lp++ )
  198.             {
  199.             case '\\':
  200.             switch ( *lp++ )
  201.             {
  202.             case 'n':
  203.                 bp[-1] = '\n'; break;
  204.             case 'r':
  205.                 bp[-1] = '\r'; break;
  206.             case 't':
  207.                 bp[-1] = '\t'; break;
  208.             case 'b':
  209.                 bp[-1] = '\b'; break;
  210.             case 'f':
  211.                 bp[-1] = '\f'; break;
  212.             case '0': case '1': case '2': case '3':
  213.             case '4': case '5': case '6': case '7':
  214.               {    int c = lp[-1] - '0';
  215.                 int d = *lp;
  216.                 if ( d >= '0' && d <= '7' )
  217.                 {    c = (c << 3) + d - '0';
  218.                     d = *++lp;
  219.                     if ( d >= '0' && d <= '7' )
  220.                     {    c = (c << 3) + d - '0';
  221.                         lp++;
  222.                     }
  223.                 }
  224.                 bp[-1] = c;
  225.                 break;
  226.               }
  227.             case 0:        /* unexpected EOF */
  228.                 lp--;
  229.                 goto out;
  230.             default:
  231.                 bp[-1] = lp[-1];
  232.             }
  233.             break;
  234.             case '(':
  235.             ++level;
  236.             break;
  237.             case ')':
  238.             if ( --level )
  239.               break;
  240.             case 0:
  241.             goto out;
  242.             default:
  243.             ;
  244.             }
  245.  out:        --bp;
  246.       }
  247.     else
  248.       {    /* Not quoted. */
  249.         while ( !(*lp == 0 || *lp == '\n' ||
  250.               (!rest && (*lp == ' ' || *lp == '\t')))
  251.               )
  252.           *bp++ = *lp++;
  253.         if ( bp == buf )    /* empty */
  254.           return NULL;
  255.       }
  256.     *bp = 0;
  257.     if ( endp )
  258.       *endp = lp;
  259.     arg = dsc_malloc(bp - buf + 1);
  260.     strcpy(arg, buf);
  261.     return arg;
  262. }
  263.  
  264. /* ------ Public routines ------ */
  265.  
  266. /*
  267.  * Copy a section of a DSC-conforming PostScript file.
  268.  * Detect %%(Begin|End)(Binary|Data) comments and copy the intervening
  269.  * data as binary if necessary.  If a sentinel is specified,
  270.  * stop copying when we reach a line that begins with the sentinel.
  271.  * If start < 0, don't seek before copying.
  272.  */
  273. private int dsc_copy_section(P6(FILE *from, FILE *to, long start, long end,
  274.                 char *line, const char *sentinel));
  275. void
  276. dsc_copy(FILE *from, FILE *to, long start, long end)
  277. {    char line[line_size];
  278.     dsc_copy_section(from, to, start, end, line, NULL);
  279. }
  280. char *
  281. dsc_copy_until(FILE *from, FILE *to, long start, long end,
  282.            const char *sentinel)
  283. {    char line[line_size];
  284.     int found = dsc_copy_section(from, to, start, end, line, sentinel);
  285.     if ( found )
  286.       {    char *ret = dsc_malloc(strlen(line) + 1);
  287.         strcpy(ret, line);
  288.         return ret;
  289.       }
  290.     return NULL;
  291. }
  292. private int
  293. dsc_copy_section(FILE *from, FILE *to, long start, long end,
  294.          char *line, const char *sentinel)
  295. {    int sent_len = (sentinel == 0 ? 0 : strlen(sentinel));
  296.  
  297.     if ( start >= 0 )
  298.       fseek(from, start, SEEK_SET);
  299.     while ( ftell(from) < end )
  300.       {    long count;
  301.         fgets(line, line_size, from);
  302.         if ( sent_len )
  303.           {    if ( !strncmp(line, sentinel, sent_len) )
  304.               return 1;
  305.           }
  306.         fputs(line, to);
  307.         if ( !has_dsc_prefix(line, "Begin") )
  308.           ;
  309.         else if ( has_lit_prefix(line + 7, "Binary:") )
  310.           copy_binary(to, from, line);
  311.         else if ( has_lit_prefix(line + 7, "Data:") )
  312.           copy_data(to, from, line);
  313.       }
  314.     return 0;
  315. }
  316.